package com.du.cloud.service.oauth.extend;

import cn.hutool.core.util.StrUtil;
import com.du.cloud.common.base.constant.RedisKeyConstants;
import com.du.cloud.common.base.utils.PassUtil;
import com.du.cloud.common.cache.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Desc:
 * Author: dushuang
 * Date: 2020/6/5
 **/
@Slf4j
public class PasswordTokenGranter extends ResourceOwnerPasswordTokenGranter {

    private final AuthenticationManager authenticationManager;

    public PasswordTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        super(authenticationManager, tokenServices, clientDetailsService, requestFactory);
        this.authenticationManager = authenticationManager;
    }

    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        Map<String, String> parameters = new LinkedHashMap(tokenRequest.getRequestParameters());
        //  check code
        String imgToken = parameters.get("imgToken");
        String verifyCode = parameters.get("verifyCode");
        if (StrUtil.isEmpty(imgToken) || StrUtil.isEmpty(verifyCode)) {
            throw new InvalidGrantException("验证码错误!");
        }
        boolean checked = checkVerifyCode(imgToken, verifyCode);
        if (!checked) {
            throw new InvalidGrantException("验证码错误!");
        }

        // 密码验证
        String username = parameters.get("username");
        // md5加密后的密码
        String password = parameters.get("password");

        parameters.remove("password");
        Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
        ((AbstractAuthenticationToken)userAuth).setDetails(parameters);

        try {
            userAuth = this.authenticationManager.authenticate(userAuth);
        } catch (AccountStatusException var8) {
            throw new InvalidGrantException(var8.getMessage());
        } catch (BadCredentialsException var9) {
            throw new InvalidGrantException(var9.getMessage());
        }

        if (userAuth != null && userAuth.isAuthenticated()) {
            OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
            return new OAuth2Authentication(storedOAuth2Request, userAuth);
        } else {
            throw new InvalidGrantException("Could not authenticate user: " + username);
        }
    }

    /**
     * 验证码校验
     * @param imgToken
     * @param verifyCode
     * @return
     */
    private boolean checkVerifyCode(String imgToken, String verifyCode) {
        log.info("[验证码校验] imgToken: {}, verifyCode: {}", imgToken, verifyCode);
        // redis缓存的验证码
        String redisCode = RedisUtil.get(RedisKeyConstants.CAPTCHA_CODE.concat(imgToken));
        return StrUtil.isNotEmpty(redisCode) && StrUtil.equals(redisCode, verifyCode, true);
    }
}
